// lofei
//
// 光影特效

// 线段
class Line {
    /** 线段开始坐标 */
    p1: cc.Vec2 = cc.v2(0, 0);
    /** 线段结束坐标 */
    p2: cc.Vec2 = cc.v2(0, 0);

    constructor(p1: cc.Vec2, p2: cc.Vec2) {
        this.p1 = p1;
        this.p2 = p2;
    }
}

const { ccclass, property } = cc._decorator;

@ccclass
export class SightAndLight extends cc.Component {

    // 绘图层
    @property({ displayName: "绘制层", tooltip: "画线", type: cc.Node })
    mDrawLayer: cc.Node = null;

    @property({ displayName: "绘制节点", type: cc.Node })
    mDrawNode: cc.Node = null;

    @property({ displayName: "静态绘制节点", type: cc.Node })
    mStaticDrawNode: cc.Node = null;

    @property({ displayName: "背景图片", type: cc.Node })
    mBackground: cc.Node = null;

    @property({ displayName: "前景图片", type: cc.Node })
    mForeground: cc.Node = null;

    @property({ displayName: "光源", type: cc.Node })
    mLightNode: cc.Node = null;

    // 光源散射数量
    @property({ displayName: "光源", tooltip: "光源散射数量" })
    mMaxLight: number = 10;

    _lightPoints: [];
    _drawNode: cc.Graphics = null;
    _staticDrawNode: cc.Graphics = null;
    _vertexs: [cc.Vec2] = [cc.v2(0, 0)];
    _segments: [Line] = [new Line(cc.v2(0, 0), cc.v2(0, 0))];
    _angles: [number] = [0];
    _mask: cc.Mask = null;
    _isAuto = true;
    _autoMovePos1: cc.Vec2 = cc.v2(0, 0);
    _autoMovePos2: cc.Vec2 = cc.v2(0, 0);

    // LIFE-CYCLE CALLBACKS:

    onLoad() {
        this._drawNode = this.mDrawNode.getComponent(cc.Graphics);
        this._staticDrawNode = this.mStaticDrawNode.getComponent(cc.Graphics);
        this._mask = this.mForeground.getComponent(cc.Mask);

        this.initVertexs();
        this.drawSegments();
        this.initSingleVertexs();

        this.node.on(cc.Node.EventType.TOUCH_START, this.touchBegan, this);
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this.touchMove, this);
        this.node.on(cc.Node.EventType.TOUCH_END, this.touchEnd, this);
        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.touchEnd, this);
    }

    start() {
        this.moveLight();
    }

    // update (dt) {}    
    backToHome() {
        cc.director.loadScene("TestItemScrollView");
    }

    touchBegan(event: cc.Event.EventTouch) {
        let touchPos = event.touch.getLocation();

        if (this.mBackground.getBoundingBoxToWorld().contains(touchPos)) {
            // this.mLightNode.position = this.mDrawLayer.convertToNodeSpaceAR(touchPos);
            this.mLightNode.stopAllActions();
            this.mLightNode.position = touchPos;
            this._isAuto = false;
            this.drawLight(touchPos);
        }
    }

    touchMove(event: cc.Event.EventTouch) {
        let touchPos = event.touch.getLocation();
        if (this.mBackground.getBoundingBoxToWorld().contains(touchPos)) {
            // this.mLightNode.position = this.mDrawLayer.convertToNodeSpaceAR(touchPos);
            this.mLightNode.stopAllActions();
            this.mLightNode.position = touchPos;
            this._isAuto = false;
            this.drawLight(touchPos);
        }
    }

    touchEnd(event: cc.Event.EventTouch) {
        let self = this;
        this.scheduleOnce(function () {
            self.moveLight();
        }, 2);
        this._isAuto = true;
    }

    moveLight() {
        return;

        let self = this;
        let size = this.mBackground.getBoundingBoxToWorld();
        this.mLightNode.position = cc.v2(size.xMin, Math.floor(Math.random() * (size.yMax - size.yMin + 1) + size.yMin));
        this.mLightNode.runAction(cc.sequence(
            cc.callFunc(function () {
                self._autoMovePos1 = cc.v2(size.xMin, Math.floor(Math.random() * (size.yMax - size.yMin + 1) + size.yMin));
                self._autoMovePos2 = cc.v2(size.xMax, Math.floor(Math.random() * (size.yMax - size.yMin + 1) + size.yMin));
                self.mLightNode.position = self._autoMovePos1;
                cc.log(JSON.stringify(self._autoMovePos1) + "  " + JSON.stringify(self._autoMovePos2));
            }),
            cc.moveTo(5, self._autoMovePos2).easing(cc.easeQuadraticActionIn()),
            cc.moveTo(5, self._autoMovePos1).easing(cc.easeQuadraticActionIn())
        ).repeatForever());
    }

    update() {
        if (this._isAuto) {
            this.drawLight(this.mLightNode.position);
        }
    }

    initVertexs() {
        this._vertexs.pop();
        // 边框
        this._vertexs.push(cc.v2(0, 0));
        this._vertexs.push(cc.v2(0, 360));
        this._vertexs.push(cc.v2(0, 360));
        this._vertexs.push(cc.v2(840, 360));
        this._vertexs.push(cc.v2(840, 360));
        this._vertexs.push(cc.v2(840, 0));
        this._vertexs.push(cc.v2(840, 0));
        this._vertexs.push(cc.v2(0, 0));

        // 左上四边形
        this._vertexs.push(cc.v2(100, 210));
        this._vertexs.push(cc.v2(120, 310));
        this._vertexs.push(cc.v2(120, 310));
        this._vertexs.push(cc.v2(200, 280));
        this._vertexs.push(cc.v2(200, 280));
        this._vertexs.push(cc.v2(140, 150));
        this._vertexs.push(cc.v2(140, 150));
        this._vertexs.push(cc.v2(100, 210));

        // 左下三角形
        this._vertexs.push(cc.v2(100, 160));
        this._vertexs.push(cc.v2(120, 110));
        this._vertexs.push(cc.v2(120, 110));
        this._vertexs.push(cc.v2(60, 60));
        this._vertexs.push(cc.v2(60, 60));
        this._vertexs.push(cc.v2(100, 160));

        // 左下四边形
        this._vertexs.push(cc.v2(200, 100));
        this._vertexs.push(cc.v2(220, 210));
        this._vertexs.push(cc.v2(220, 210));
        this._vertexs.push(cc.v2(300, 160));
        this._vertexs.push(cc.v2(300, 160));
        this._vertexs.push(cc.v2(350, 40));
        this._vertexs.push(cc.v2(350, 40));
        this._vertexs.push(cc.v2(200, 100));

        // 右上三角形
        this._vertexs.push(cc.v2(540, 300));
        this._vertexs.push(cc.v2(560, 320));
        this._vertexs.push(cc.v2(560, 320));
        this._vertexs.push(cc.v2(570, 290));
        this._vertexs.push(cc.v2(570, 290));
        this._vertexs.push(cc.v2(540, 300));

        // 右上三角形
        this._vertexs.push(cc.v2(600, 265));
        this._vertexs.push(cc.v2(780, 310));
        this._vertexs.push(cc.v2(780, 310));
        this._vertexs.push(cc.v2(680, 210));
        this._vertexs.push(cc.v2(680, 210));
        this._vertexs.push(cc.v2(600, 265));

        // 右下四边形
        this._vertexs.push(cc.v2(650, 170));
        this._vertexs.push(cc.v2(760, 190));
        this._vertexs.push(cc.v2(760, 190));
        this._vertexs.push(cc.v2(740, 90));
        this._vertexs.push(cc.v2(740, 90));
        this._vertexs.push(cc.v2(630, 70));
        this._vertexs.push(cc.v2(630, 70));
        this._vertexs.push(cc.v2(650, 170));

        for (let i in this._vertexs) {
            this._vertexs[i] = this._vertexs[i].add(cc.v2((cc.winSize.width - 840) / 2, (cc.winSize.height - 360) / 2));
        }
    }

    drawSegments() {
        this._segments.pop();
        this._staticDrawNode.fillColor = new cc.Color(0, 255, 0, 255)
        this._staticDrawNode.lineWidth = 1;
        for (let i = 0; i < this._vertexs.length; i += 2) {
            let startPos = this._vertexs[i];
            let endPos = this._vertexs[i + 1];
            this._segments.push(new Line(startPos, endPos));

            this._staticDrawNode.moveTo(startPos.x, startPos.y);
            this._staticDrawNode.lineTo(endPos.x, endPos.y);
            this._staticDrawNode.close();
            this._staticDrawNode.stroke();
        }
    }

    drawLight(pos: cc.Vec2) {
        this._drawNode.clear();
        this._drawNode.fillColor = new cc.Color(255, 255, 255, 100)

        this._angles = [0];
        this._angles.pop();

        // this._drawNode.moveTo(this.mDrawLayer.width / 2, this.mDrawLayer.height / 2);
        // this._drawNode.lineTo(pos.x, pos.y);
        // this._drawNode.close();
        // this._drawNode.stroke();

        let vertex = [this.calcAngles(pos)];
        let radius = 10;
        for (let i = 0; i < Math.PI * 2; i += (Math.PI * 2) / 10) {
            let dx = Math.cos(i) * radius;
            let dy = Math.sin(i) * radius;
            vertex.push(this.calcAngles(pos.add(cc.v2(dx, dy))));
        }

        let limit = vertex.length;
        this._drawNode.lineWidth = 6;
        this._drawNode.fillColor = new cc.Color(255, 255, 255, 100)
        // this._drawNode.moveTo(vertex[0].x, vertex[0].y);
        for (let i = 1; i < limit; i++) {
            // this._drawNode.moveTo(this.mDrawLayer.width / 2, this.mDrawLayer.height / 2);
            // cc.log("连线[ " + i + " ]: " + JSON.stringify(vertex[i]) + " to " + JSON.stringify(vertex[i + 1]));
            // this._drawNode.lineTo(vertex[i].x, vertex[i].y);
            this.drawPolygon(vertex[i], new cc.Color(255, 255, 255, 20));
            // this._drawNode.lineTo(vertex[i + 1].x, vertex[i + 1].y);
            // this._drawNode.lineTo(pos.x, pos.y);

            // this._drawNode.moveTo(this.mDrawLayer.width / 2, this.mDrawLayer.height / 2);

            // this._drawNode.fillColor = new cc.Color(i * 50 + this.mMaxLight, 0, 0, 255)
            // this._drawNode.circle(vertex[i].x, vertex[i].y, 10);
            // this._drawNode.fill();
        }
        this.drawPolygon(vertex[0], new cc.Color(255, 255, 255, 80));
        // this._drawNode.close();
        // this._drawNode.fill();

        // 鼠标光圈
        for (let i = 0; i < Math.PI * 2; i += (Math.PI * 2) / 10) {
            let dx = Math.cos(i) * radius;
            let dy = Math.sin(i) * radius;
            this._drawNode.arc(pos.x + dx, pos.y + dy, 2, 0, 2 * Math.PI);
            this._drawNode.fill();

        }
        // this._drawNode.lineWidth = 1;
        // this._drawNode.fillColor = new cc.Color(255, 255, 255, 100)
        // for (let i =0 ; i < limit; i++) {
        //     this._drawNode.moveTo(pos.x, pos.y);
        //     this._drawNode.lineTo(vertex[i].x, vertex[i].y);
        //     this._drawNode.stroke();

        //     this._drawNode.fillColor = new cc.Color(i * 50 + limit, 0, 0, 255)
        //     this._drawNode.circle(vertex[i].x, vertex[i].y, 5);
        //     this._drawNode.fill();
        // }
        if (limit > 0) {
            // this._drawNode.moveTo(pos.x, pos.y);
            // this._drawNode.lineTo(vertex[limit].x, vertex[limit].y);
            // this._drawNode.lineTo(vertex[0].x, vertex[0].y);
            // this._drawNode.lineTo(pos.x, pos.y);
            // this._drawNode.close();
            // this._drawNode.fill();
        }
    }

    drawPolygon(polygon, color: cc.Color) {
        this._drawNode.fillColor = color;
        this._drawNode.moveTo(polygon[0].x, polygon[0].y);
        for (let i = 1; i < polygon.length; i++) {
            this._drawNode.lineTo(polygon[i].x, polygon[i].y);
        }
        this._drawNode.fill();
    }

    initSingleVertexs() {
        let poss: [cc.Vec2] = [cc.v2(0, 0)];
        poss.pop();
        for (let i = 0; i < this._vertexs.length; i++) {
            let find = false;
            for (let k = 0; k < poss.length; k++) {
                if (this._vertexs[i].x == poss[k].x && this._vertexs[i].y == poss[k].y) {
                    find = true;
                    break;
                }
            }

            if (!find) {
                poss.push(this._vertexs[i]);
            }
        }

        this._vertexs = [cc.v2(0, 0)];
        this._vertexs.pop();
        for (let i in poss) {
            this._vertexs.push(poss[i]);
        }
    }

    calcAngles(touchPos: cc.Vec2) {
        let eps = 1e-4;
        for (let i = 0; i < this._vertexs.length; i++) {
            // if (this._angles.length >= 2) {
            // break;
            // }
            let angle = Math.atan2(this._vertexs[i].y - touchPos.y, this._vertexs[i].x - touchPos.x);
            this._angles.push(angle - eps);
            this._angles.push(angle + eps);
            // this._angles.push(360 / this.mMaxLight * (i + 1));
        }

        this._angles.sort();
        let tar: cc.Vec2 = cc.v2(0, 0);
        let allVertex = [];
        for (let i in this._angles) {
            let dlt = cc.v2(Math.cos(this._angles[i]), Math.sin(this._angles[i]));
            let closest = -1;

            for (let k in this._segments) {

                // cc.log("视线坐标：" + JSON.stringify(new Line(centerPos, pos)) + ", 检查线段[ " + k + " ]：" + JSON.stringify(this._segments[k]));
                let result = this.getIntersection(new Line(touchPos, touchPos.add(dlt)), this._segments[k]);
                if (result) {
                    if (closest == -1 || closest > result.distance) {
                        closest = result.distance;
                        tar = result.p;
                    }
                }
            }
            if (closest != -1) {
                allVertex.push({
                    closest: this._angles[i],
                    vertex: tar
                });
            }
        }

        allVertex.sort(function (a, b) {
            return a.closest - b.closest;
        });

        let tmp = [];
        for (let i in allVertex) {
            tmp.push(allVertex[i].vertex);
        }

        return tmp;
    }

    getCross(p1: cc.Vec2, p2: cc.Vec2) {
        return (p1.x * p2.y - p1.y * p2.x);
    }

    getFloat(num: number) {
        return num;
        // return Math.floor(num * 1e4) / 1e4;
    }

    getIntersection(ray: Line, segment: Line) {
        let r_px = this.getFloat(ray.p1.x);
        let r_py = this.getFloat(ray.p1.y);
        let r_dx = this.getFloat(ray.p2.x - ray.p1.x);
        let r_dy = this.getFloat(ray.p2.y - ray.p1.y);

        let s_px = this.getFloat(segment.p1.x);
        let s_py = this.getFloat(segment.p1.y);
        let s_dx = this.getFloat(segment.p2.x - segment.p1.x);
        let s_dy = this.getFloat(segment.p2.y - segment.p1.y);

        let r_mag = Math.sqrt(r_dx * r_dx + r_dy * r_dy);
        let s_mag = Math.sqrt(s_dx * s_dx + s_dy * s_dy);

        if (r_dx / r_mag == s_dx / s_mag && r_dy / r_mag == s_dy / s_mag) {
            return false;
        }

        let t2 = (r_dx * (s_py - r_py) + r_dy * (r_px - s_px)) / (s_dx * r_dy - s_dy * r_dx);
        let t1 = (s_px + s_dx * t2 - r_px) / r_dx;

        if (t1 < 0) {
            return false;
        }
        if (t2 < 0 || t2 > 1) {
            return false;
        }

        return {
            p: cc.v2(r_px + r_dx * t1, r_py + r_dy * t1),
            distance: t1
        }
    }
}
